package ja12resttemplate.util;

import com.alibaba.fastjson2.JSONObject;
import ja12resttemplate.util.AssertUtil;
import org.apache.commons.compress.utils.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.*;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.Set;

/**
 * http 请求处理客户端
 * @author mrh
 *
 */
public class HttpClientUtil {
	private static final Logger logger = LoggerFactory.getLogger(HttpClientUtil.class);
	/**
	 * 200 访问正常
	 */
	private static final int STATU_CODE_NOMAL = 200;

	/**
	 * http request method GET
	 */
	private static final String HTTP_METHOD_GET = "GET";

	/**
	 * http request method POST
	 */
	private static final String HTTP_METHOD_POST = "POST";

	/**
	 * 下载文件流
	 */
	private static final String CONTENT_TYPE_MSDOWNLOAD = "application/x-msdownload";

	/**
	 * 执行GET方式的请求
	 * @param urlStr
	 * @param reqPros 请求属性
	 * @return
	 * @throws Exception
	 */
	public static final JSONObject get(String urlStr, Map<String, String> reqPros) throws Exception {
		return excute(urlStr, HTTP_METHOD_GET, null, reqPros);
	}

	/**
	 * 执行GET方式的请求
	 * @param urlStr
	 * @return
	 * @throws Exception
	 */
	public static final JSONObject get(String urlStr) throws Exception {
		return excute(urlStr, HTTP_METHOD_GET, null, null);
	}


	/**
	 * 执行POST方式的请求
	 * @param urlStr
	 * @param paramMap
	 * @return
	 * @throws Exception
	 * @
	 */
	public static final JSONObject post(String urlStr, Map<String, Object> paramMap, Map<String, String> reqPros) throws Exception {
		return excute(urlStr, HTTP_METHOD_POST, paramMap, reqPros);
	}

	/**
	 * 执行POST方式的请求
	 * @param urlStr
	 * @param paramMap
	 * @return
	 * @throws Exception
	 * @
	 */
	public static final JSONObject post(String urlStr, Map<String, Object> paramMap) throws Exception {
		return excute(urlStr, HTTP_METHOD_POST, paramMap, null);
	}

	/**
	 * 执行http请求
	 * @param urlStr
	 * @param httpMethod
	 * @param paramMap
	 * @param reqPros	请求头信息
	 * @return
	 * @throws Exception
	 */
	private static JSONObject excute(String urlStr, String httpMethod, Map<String, Object> paramMap, Map<String, String> reqPros) throws Exception{
		URL url = new URL(urlStr);
		HttpURLConnection connection = (HttpURLConnection) url.openConnection();
		connection.setDoInput(true);
		if (HTTP_METHOD_GET.equals(httpMethod)) {
			connection.setDoOutput(false);
		} else {
			connection.setDoOutput(true);
		}
		connection.setRequestMethod(httpMethod);

		if (AssertUtil.isVal(reqPros)) {
			Set<String> keySet = reqPros.keySet();
			for (String key : keySet) {
				connection.setRequestProperty(key, reqPros.get(key));
			}
		} else {
			connection.setRequestProperty("Accept", "application/json");
			connection.setRequestProperty("Content-Type", "application/json; charset=" + EncodeUtil.getEncode());
		}

		connection.connect();
		return excuteBase(urlStr, paramMap, connection);
	}

	private static JSONObject excuteBase(String urlStr, Map<String, Object> paramMap, HttpURLConnection connection)
			throws UnsupportedEncodingException, IOException, ConnectException {
		JSONObject result = null;
		if (connection.getDoOutput()) {
			JSONObject obj = new JSONObject();
			if (AssertUtil.isVal(paramMap)) {
				obj.putAll(paramMap);
			}
			OutputStreamWriter water = new OutputStreamWriter(connection.getOutputStream(), EncodeUtil.getEncode());
			water.write(obj.toJSONString());
			water.flush();
			water.close();
		}

		if (connection.getDoInput()) {
			int responseCode = connection.getResponseCode();

			String contentType = connection.getContentType();
			if (AssertUtil.isVal(contentType) && contentType.contains(CONTENT_TYPE_MSDOWNLOAD)) {
				InputStream is = connection.getInputStream();
				byte[] bytes = IOUtils.toByteArray(is);

	            JSONObject headMap = new JSONObject();
	            headMap.putAll(connection.getHeaderFields());

	            result = new JSONObject();
	            result.put("fileBytes", bytes);
	            result.put("headInfo", headMap);

	            return result;
			}

			BufferedReader bufferedReader = new BufferedReader(
					new InputStreamReader(connection.getInputStream(), EncodeUtil.getEncode()));
			String line = "";
			StringBuffer strBuffer = new StringBuffer();
			while ((line = bufferedReader.readLine()) != null) {
				strBuffer.append(line);
			}

			if (responseCode != STATU_CODE_NOMAL) {
				throw new ConnectException(urlStr + "请求失败！状态码：" + responseCode + ",错误内容：" + strBuffer);
			}
			logger.debug("返回内容：" + strBuffer);

			// 如果以双引号开头和结尾的json，需要去掉后再转换
			String jsonValue = strBuffer.toString();
			if (jsonValue.startsWith("\"")) {
				jsonValue = jsonValue.substring(1, jsonValue.length() - 1);
			}
			if (RestFulUtil.JsonValid(jsonValue)) {
				result = JSONObject.parseObject(jsonValue);
			}
		}
		return result;
	}



	/**
	 * 执行GET方式的请求
	 * @param urlStr
	 * @param paramMap
	 * @return
	 * @throws Exception
	 */
	public static final JSONObject httpsGget(String urlStr, Map<String, String> reqPros) throws Exception {
		return httpsExcute(urlStr, HTTP_METHOD_GET, null, reqPros);
	}

	/**
	 * 执行GET方式的请求
	 * @param urlStr
	 * @return
	 * @throws Exception
	 */
	public static final JSONObject httpsGet(String urlStr) throws Exception {
		return httpsExcute(urlStr, HTTP_METHOD_GET, null, null);
	}


	/**
	 * 执行POST方式的请求
	 * @param urlStr
	 * @param paramMap
	 * @return
	 * @throws Exception
	 * @
	 */
	public static final JSONObject httpsPost(String urlStr, Map<String, Object> paramMap) throws Exception {
		return httpsExcute(urlStr, HTTP_METHOD_POST, paramMap, null);
	}

	/**
	 * 执行POST方式的请求
	 * @param urlStr
	 * @param paramMap
	 * @return
	 * @throws Exception
	 * @
	 */
	public static final JSONObject httpsPost(String urlStr, Map<String, Object> paramMap, Map<String, String> reqPros) throws Exception {
		return httpsExcute(urlStr, HTTP_METHOD_POST, paramMap, reqPros);
	}

	/**
	 * 执行https请求
	 * @param urlStr String
	 * @param httpMethod String
	 * @param paramMap  Map<String, String>
	 * @return the json Object String
	 * @throws Exception
	 */
	private static JSONObject httpsExcute(String urlStr, String httpMethod, Map<String, Object> paramMap, Map<String, String> reqPros) throws Exception{

		SSLContext sslcontext = SSLContext.getInstance("TLS");
        sslcontext.init(null, new TrustManager[]{myX509TrustManager}, null);

		URL url = new URL(urlStr);

		HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
		connection.setSSLSocketFactory(sslcontext.getSocketFactory());
		connection.setDoInput(true);
		if (HTTP_METHOD_GET.equals(httpMethod)) {
			connection.setDoOutput(false);
		} else {
			connection.setDoOutput(true);
		}
		connection.setRequestMethod(httpMethod);

		if (AssertUtil.isVal(reqPros)) {
			Set<String> keySet = reqPros.keySet();
			for (String key : keySet) {
				connection.setRequestProperty(key, reqPros.get(key));
			}
		} else {
			connection.setRequestProperty("Accept", "application/json");
			connection.setRequestProperty("Content-Type", "application/json; charset=" + EncodeUtil.getEncode());
		}
		connection.connect();
		return excuteBase(urlStr, paramMap, connection);
	}

	private static TrustManager myX509TrustManager = new X509TrustManager() {

		@Override
		public X509Certificate[] getAcceptedIssuers() {
			return null;
		}

		@Override
		public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
		}

		@Override
		public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
		}
	};

}
